﻿using System;
using System.Collections.Generic;
using System.Linq;


namespace Playkanaler.WebPageSource.HtmlParser
{


    public enum TType { NotDef, StartTag, StartEnd, EndTag, Text, Comment, Decl };

    class Tag
    {
        public TType type=new TType();
        public string text="";
        public string name="";
        public Dictionary<string, string> attribute=new Dictionary<string,string>();
        public List<Tag> children=new List<Tag>();

        public override string ToString()
        {
            string na = name + " [";
            foreach (var a in attribute)
            {
                na += a.Key + " = " + a.Value + ", ";
            }
            na += "]";
            return na;
        }

        public bool HasChild()
        {
            return Children().Count > 0;
        }
        public bool HasChild(string name)
        {
            return Children(name).Count>0;
        }
        public bool HasChild(string name, params string[] attr)
        {
            return Children(name, attr).Count > 0;
        }

        public Tag Child()
        {
            return Children().Last();
        }
        public Tag Child(string name)
        {
            return Children(name).Last();
        }
        public Tag Child(string name,params string[] attr)
        {
            return Children(name,attr).Last();
        }

        public List<Tag> Children()
        {
            return children;
        }
        public List<Tag> Children(string name)
        {
             return (from c in children where c.name==name select c).ToList();
        }
        public List<Tag> Children(string name,params string[] attr)
        {
            List<Tag> nl = new List<Tag>();
            foreach (var c in children)
            {
                if (c.name == name)
                {
                    if (attr == null)
                    {
                        if (c.attribute.Count != 0) continue;
                    }
                    else
                    {
                        bool b = false;
                        for (int i = 0; i < attr.Count(); i += 2)
                        {
                            b = false;
                            string n = attr[i];
                            string v = attr[i + 1];
                            if (c.attribute.ContainsKey(n))
                            {
                                b = (c.attribute[n] == v);
                            }
                            else
                            {
                                break;
                            }


                        }
                        if (!b) continue;
                    }
                    nl.Add(c);
                }
            }
            return nl;
        }
        

    }
    class HtmlDoc
    {

        string text;


         ~HtmlDoc()
        {

        }

         public List<Tag> tags = new List<Tag>();
        public void Parse(string str)
        {
            char status = '0';
            bool qoute = false;
            char qc = '\0';
            text = str;
            int len = str.Length;
            string buffer;
            Tag tag=new Tag();
            string an="";
            string av="";
            string com = "";
            buffer = com;
            bool endtag = false;

            bool tcc = false;


            for (int i = 0; i < len; i++)
            {

                char c = str[i];


                if (c == '\\') continue;
                if (i > 0 && str[i - 1] == '\\') continue;

                if ((c == '\"' || c == '\'') && status != '0')
                {
                    if (qoute && qc == c) qoute = false;
                    else if (!qoute)
                    {
                        qoute = true;
                        qc = c;
                    }
                }
                else if (!qoute)
                {
                    if (status == '0')
                    {
                        if (c == '<')
                        {
                            tag.type = TType.Text;
                            tags.Add(tag);
                            tag = new Tag();
                            tag.type = TType.NotDef;
                            tag.text = "";
                            status = '<';
                            tag.type = TType.StartTag;
                        }
                        else
                        {
                            tag.text += c;
                        }

                    }
                    else if (status == '<')
                    {

                        if (c == ' ')
                        {
                            status = 'a';
                            an = "";
                        }
                        else if (c == '/')
                        {
                            tag.type = TType.EndTag;
                            if (str[i + 1] == '>') tag.type = TType.StartEnd;

                        }
                        else if (c == '!')
                        {
                            status = '!';
                            buffer = com;
                            tcc = (str[i + 1] == '-' && str[i + 2] == '-');
                            
                        }
                        else if (c == '>')
                        {
                            status = '>';
                        }
                        else
                        {
                            tag.name += c;
                        }
                    }
                    else if (status == '!')
                    {
                        if (c == '>')
                        {
                            if (tcc)
                            {
                                if (str[i - 1] == '-' && str[i - 2] == '-') status = '0';
                            }
                            else
                            {
                                status = '0';
                            }

                        }
                    }
                    else if (status == 'a')
                    {
                        if (c == ' ')
                        {

                        }
                        else if (c == '=')
                        {
                            status = 'v';
                            av = ""; 
                            buffer = av;
                        }
                        else if (c == '/')
                        {

                            tag.type = TType.StartEnd;
                        }
                        else if (c == '>')
                        {
                            status = '>';
                        }
                        else
                        {
                            an += c;
                        }
                    }
                    else if (status == 'v')
                    {

                       
                        if (c == ' ')
                        {
                            if (buffer != "") av = buffer;
                            if (an != "") tag.attribute[an] = av;
                            status = 'a';
                            an = "";
                        }
                        else if (c == '>')
                        {
                            if (buffer != "") av = buffer;
                            status = '>';
                            if (an != "") tag.attribute[an] = av;
                            an = "";
                            av = "";
                        }
                        else if (c == '/')
                        {
                            if (buffer != "") av = buffer;
                            tag.type = TType.StartEnd;

                            if (an != "") tag.attribute[an] = av;
                            an = "";
                            av = "";

                        }
                        else
                        {
                            av += c;
                        }

                    }
                    else if (status == 's')
                    {
                        if (c == '<' && (i + 9 < len))
                        {

                            if ((str[i + 1] == '/' && str[i + 2] == 's') || (str[i + 1] == '/' && str[i + 2] == 'S'))
                            {
                                tag.type = TType.EndTag;
                                tag.name = "script";
                                status = '>';
                                i += 8;
                            }
                        }

                    }

                    if (status == '>')
                    {
                        tags.Add(tag);
                        tag = new Tag();
                        status = '0';
                        if ((tag.name == "SCRIPT" || tag.name == "script") && tag.type == TType.StartTag)
                        {
                            status = 's';
                        }
                        tag.name = "";
                        tag.attribute.Clear();
                        tag.type = TType.NotDef;
                        tag.text = "";



                    }

                }
                else
                {
                    buffer += c;
                }

            }


        }

        public Tag Root;


        public void CreateTree()
        {


            Stack<Tag> stack = new Stack<Tag>(); ;

            Root = (tags[tags.Count - 1]);

            for (int i = tags.Count - 1; i >= 0; i--)
            {


                Tag tag = (tags[i]);

                if (tag.type == TType.EndTag)
                {
                    if (stack.Count != 0)
                    {
                        stack.Peek().children.Add(tag);
                    }
                    stack.Push(tag);
                }
                else if (tag.type == TType.StartEnd)
                {
                    stack.Peek().children.Add(tag);
                }
                else if (tag.type == TType.StartTag)
                {
                    if (string.Compare(stack.Peek().name, tag.name, true) == 0)
                    {
                        stack.Peek().type = TType.StartTag;
                        stack.Peek().attribute = tag.attribute;

                        stack.Pop();

                    }
                    else
                    {
                        tag.type = TType.StartEnd;
                        stack.Peek().children.Add(tag);
                    }
                }
                else if (tag.type == TType.Text)
                {
                    if (stack.Count != 0)
                    {


                        stack.Peek().text = tag.text + stack.Peek().text;
                    }
                }


            }

        }




        




    }
}